/*  Novelties: A visual novel programming language based on JavaFX
    Copyright (C) 2008  Hao Xu
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * /
 /*
 * Main.fx
 *
 * Created on Apr 7, 2008, 4:11:56 PM
 *//*
  * Action.fx
  *
  * Created on Apr 14, 2008, 7:39:23 PM
  */

package avgengine.script;

import avgengine.*;
import avgengine.pred.*;
import javafx.ui.canvas.*;
import javafx.ui.*;
import java.lang.Thread;
/**
 * @author ertri
 */

class Action {
    attribute asynchronous:boolean;
    operation doSynch(s:ScriptedScene);
    operation doAsynch(s:ScriptedScene, o: operation(scene:String));
}

class ActorEnters extends Action {
    attribute actorName:String;
    attribute exp:String;
    attribute side:int;
    attribute anchor:String;
}
attribute ActorEnters.asynchronous =false;
operation ActorEnters.doSynch(s) {
    println("{side},{exp},{anchor}");
    s.actorEnters(actorName,side,anchor,exp);
}


class ActorReenters extends Action {
    attribute actorName:String;
    attribute side:int;
    attribute anchor:String;
}
attribute ActorReenters.asynchronous = false;
operation ActorReenters.doSynch(s) {
    s.actorEnters(actorName,side,null,anchor);
}

class ActorExits extends Action {
    attribute actorName:String;
    attribute side:int;
}
attribute ActorExits.asynchronous = false;
operation ActorExits.doSynch(s) {
    s.actorExits(actorName,side);
}
class ActorChanges extends Action {
    attribute actorName:String;
    attribute exp:String;
}
attribute ActorChanges.asynchronous = false;
operation ActorChanges.doSynch(s) {
    s.actorChanges(actorName,null, exp);
}
class ActorMoves extends Action {
    attribute actorName:String;
    attribute anchor:String;
}
attribute ActorMoves.asynchronous = false;
operation ActorMoves.doSynch(s) {
    s.actorChanges(actorName,anchor, null);
}

//load defintions defined in Computible.fx;
Computible{};

class ActorShowsOnMap extends Action {
    attribute actorName:String;
    attribute x:Term;
    attribute y:Term;
    attribute vnfx:VNFX;
    
}
attribute ActorShowsOnMap.asynchronous = false;

function natTermToInt(t:Term):int {
    return ((Nat)((FunctionTerm)t).f).num;//,
}
operation ActorShowsOnMap.doSynch(s) {
    var comp = Computible{};
    var tx = comp.computeFold(x, vnfx);
    var ty = comp.computeFold(y, vnfx);
    s.actorShowsOnMap(actorName,natTermToInt(tx), natTermToInt(ty));
}
class ActorMovesOnMap extends Action {
    attribute actorName:String;
    attribute x:Term;
    attribute y:Term;
    attribute vnfx:VNFX;
    
}
attribute ActorMovesOnMap.asynchronous = false;
operation ActorMovesOnMap.doSynch(s) {
    var comp = Computible{};
    var tx = comp.computeFold(x, vnfx);
    var ty = comp.computeFold(y, vnfx);
    s.actorMovesOnMap(actorName,natTermToInt(tx), natTermToInt(ty));
}
class ActorHidesOnMap extends Action {
    attribute actorName:String;
    
}
attribute ActorHidesOnMap.asynchronous = false;
operation ActorHidesOnMap.doSynch(s) {
    s.actorHidesOnMap(actorName);
}
class Jump extends Action {
    attribute name:String;
}
attribute Jump.asynchronous = true;
operation Jump.doAsynch(s, o) {
    //s.fadeOff();
    o(name);
}
class Wait extends Action {
    attribute msec:int;
}
attribute Wait.asynchronous = true;
operation Wait.doAsynch(s,o) {
    do {
        println("sleep {msec}");
        Thread.sleep(msec);
        println("wake up");
        
    }
    do later {
        o(null);
    }
}
class ActorSays extends Action {
    attribute actorName:String;
    attribute pstring:String;
}
attribute ActorSays.asynchronous = true;
operation ActorSays.doAsynch(s, o) {
    println("ActorSays.doAsynch:{actorName},{pstring}");
    s.actorSays(actorName,pstring);
    s.waitForClick(
    operation(e:CanvasMouseEvent):boolean {
        println("CanvasMouseEvent {e}");
        return false;
    },
    operation() {
        // wait for click button to fade out.
        do {
            Thread.sleep(100);
        }
        o(null);
        
    });
}
operation ActorSays.doSynch(s) {
    println("ActorSays.doSynch:{actorName},{pstring}");
    s.actorSays(actorName,pstring);
}
class Choose extends Action {
    attribute choices:String*;
    attribute branchNames:String*;
}

attribute Choose.asynchronous = true;
operation Choose.doAsynch(s, o) {
    println("Choose.doAsynch: {choices},{branchNames}");
    s.choose(choices,
    operation(i:int){
        println("Go to branch: {branchNames[i]}");
        var b:String = branchNames[i];
        o(b);
    });
    
}

class GuardedAction extends Action {
    attribute action:Action;
    attribute guard:Literal*;
    attribute clauseMap: ClauseMap;
    attribute env: Substitution;
}

attribute GuardedAction.asynchronous = bind action.asynchronous;

operation GuardedAction.doAsynch(s, o) {
    var inst = env.subLiterals(guard);
    if(sizeof clauseMap.query(inst) > 0) {
        println("{clauseMap.query(inst)}");
        action.doAsynch(s, o);
    } else {
        o(null);
    }
}

operation GuardedAction.doSynch(s) {
    var inst = env.subLiterals(guard);
    if(sizeof clauseMap.query(inst) > 0) {
        println("{clauseMap.query(inst)}");
        
        action.doSynch(s);
    } else {
    }
}

class SetAction extends Action {
    attribute env: Substitution;
    attribute variable: Variable;
    attribute term: Term;
    attribute vnfx: VNFX;
    
}

attribute SetAction.asynchronous = false;
operation SetAction.doSynch(s) {
    var comp = Computible{};
    var sub = Substitution{};
    sub.put(variable, term);
    println("set {variable} = {sub}");
    var nsub = this.env.subSub(sub);
    println("set {variable} = {nsub}");
    env.put(variable, comp.computeFold((Term)nsub.map.get(variable.n),vnfx));
}